#include "stdafx.h"
#include "WindowsCommon.h"
#include "Window.h"

using namespace Hiranipra;
using namespace Hiranipra::Platform;

#define WINDOW_CLASS_NAME L"HiranipraWindow"
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );

bool _hasWindowClass = false;
bool _hasWindowMetrics = false;
Size2D _nonClientPadding;
map<HWND, Window*> _windows;

Window::Window( const WindowParameters& params )
{
	HINSTANCE hInstance = NULL;

	if( _hasWindowClass == false )
	{
		WNDCLASS wc;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = 0;
		wc.hbrBackground = ( HBRUSH )GetStockObject( WHITE_BRUSH );
		wc.hCursor = LoadCursor( NULL, IDC_ARROW );
		wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
		wc.hInstance = hInstance;
		wc.lpfnWndProc = WndProc;
		wc.lpszClassName = WINDOW_CLASS_NAME;
		wc.lpszMenuName = 0;
		wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
		RegisterClass( &wc );
		_hasWindowClass = true;
	}

	float w = params.DefaultSize.w + _nonClientPadding.w;
	float h = params.DefaultSize.h + _nonClientPadding.h;
	
	_handle = CreateWindowEx(
		WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
		WINDOW_CLASS_NAME,
		params.DefaultTitle.c_str(),
		WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
		CW_USEDEFAULT, CW_USEDEFAULT,
		( int )w, ( int )h,
		NULL, NULL,
		hInstance, NULL );

	ShowWindow( _handle, SW_SHOW );
	UpdateWindow( _handle );

	if( _hasWindowMetrics == false )
	{
		RECT rect;
		GetClientRect( _handle, &rect );
		_nonClientPadding.w = params.DefaultSize.w - rect.right;
		_nonClientPadding.h = params.DefaultSize.h - rect.bottom;
		w = params.DefaultSize.w + _nonClientPadding.w;
		h = params.DefaultSize.h + _nonClientPadding.h;
		SetWindowPos( _handle, NULL, 0, 0, ( int )w, ( int )h, SWP_NOZORDER | SWP_NOMOVE );
		_hasWindowMetrics = true;
	}

	this->Retain();
	_windows[ _handle ] = this;
	_isClosed = false;
}

Window::~Window()
{
	if( _isClosed == false )
		this->Close();
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	Window* window = _windows[ hWnd ];
	if( window == NULL )
		return DefWindowProc( hWnd, msg, wParam, lParam );

	switch( msg )
	{
	case WM_CREATE:
		break;

	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hDC = BeginPaint( hWnd, &ps );
			// Clear, etc
			EndPaint( hWnd, &ps );
		}
		break;

	case WM_KEYDOWN:
		switch( wParam )
		{
		case VK_ESCAPE:
			PostQuitMessage( 0 );
			break;
		default:
			break;
		}
		break;

	case WM_SIZE:
		switch( wParam )
		{
		case SIZE_MAXIMIZED:
		case SIZE_MINIMIZED:
		case SIZE_RESTORED:
			window->EventSource.Fire( WindowEvent( window, WindowEvent::SizeChanged ) );
			break;
		}
		break;

	case WM_CLOSE:
		window->Close();
		break;

	case WM_DESTROY:
		_windows.erase( hWnd );
		window->Release();
		break;
	}

	return DefWindowProc( hWnd, msg, wParam, lParam );
}

void Window::SetTitle( const wstring& newTitle )
{
	if( _isClosed == true )
		return;
	SetWindowText( _handle, newTitle.c_str() );
}

uint32 Window::GetCurrentDisplay() const
{
	if( _isClosed == true )
		return 0;
	// TODO: GetCurrentDisplay
	return 0;
}

void Window::MoveToDisplay( const uint32 displayId )
{
	if( _isClosed == true )
		return;
	// TODO: MoveToDisplay
}

Point2D Window::GetLocation() const
{
	if( _isClosed == true )
		return Point2D( 0, 0 );
	RECT rect;
	GetWindowRect( _handle, &rect );
	return Point2D( ( float )rect.left, ( float )rect.top );
}

void Window::SetLocation( const Point2D& location )
{
	if( _isClosed == true )
		return;
	SetWindowPos( _handle, NULL, ( int )location.x, ( int )location.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE );
}

Size2D Window::GetSize() const
{
	if( _isClosed == true )
		return Size2D( 1, 1 );
	RECT rect;
	GetClientRect( _handle, &rect );
	return Size2D( ( float )rect.right, ( float )rect.bottom );
}

void Window::SetSize( const Size2D& size )
{
	if( _isClosed == true )
		return;
	float w = size.w + _nonClientPadding.w;
	float h = size.h + _nonClientPadding.h;
	SetWindowPos( _handle, NULL, 0, 0, ( int )w, ( int )h, SWP_NOZORDER | SWP_NOMOVE );
}

WindowState Window::GetState() const
{
	if( _isClosed == true )
		return Normal;
	// TODO: GetState
	return Normal;
}

void Window::SetState( const WindowState state )
{
	if( _isClosed == true )
		return;
	// TODO: SetState
}

bool Window::IsMinimized() const
{
	if( _isClosed == true )
		return false;
	// TODO: IsMinimized
	return false;
}

void Window::Close()
{
	if( _isClosed == true )
		return;
	_isClosed = true;
	CloseWindow( _handle );
	_handle = NULL;
	this->EventSource.Fire( WindowEvent( this, WindowEvent::Closed ) );
}
